/*
 * Copyright 2008 The Brui Team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at 
 *
 * 	http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */

package com.googlecode.brui.components.tree;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.List;

import javax.swing.event.TreeModelListener;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import com.googlecode.brui.beans.Bean;
import com.googlecode.brui.beans.Property;

/**
 * Tree model which provides access to beans within an object graph. Bean
 * properties which are not considered beans themselves (primitives, Strings,
 * dates etc) will not be included as nodes in the tree model. TODO collection
 * behaviour
 */
public class BeanTreeModel implements TreeModel, Serializable {

	private static final long serialVersionUID = 1L;

	private final Collection<TreeModelListener> modelListeners = new HashSet<TreeModelListener>();

	private Object root;

	public BeanTreeModel() {

	}

	public BeanTreeModel(final Object root) {
		this.root = root;
	}

	@Override
	public Object getRoot() {
		return root;
	}

	public void setRoot(final Object root) {
		this.root = root;
	}

	private Bean getBean(final Object object) {
		return new Bean(object);
	}

	@Override
	public Object getChild(final Object parent, final int index) {
		final Bean bean = getBean(parent);
		return bean.getProperties().get(index).getValue();
	}

	@Override
	public int getChildCount(final Object parent) {
		int childCount = 0;
		final Bean bean = getBean(parent);
		for (final Property property : bean.getProperties()) {
			final Object value = property.getValue();
			if (value == null || isSimpleType(value)) {
				continue;
			}
			childCount++;
		}
		return childCount;
	}

	@Override
	public int getIndexOfChild(final Object parent, final Object child) {
		if (parent == null || child == null) {
			return -1;
		}
		final Bean bean = getBean(parent);
		final List<Property> properties = bean.getProperties();
		for (int i = 0; i < properties.size(); i++) {
			final Property property = properties.get(i);
			if (child.equals(property.getValue())) {
				// Note that this index may be incorrect if there are multiple bean
				// fields with equal values. This same problem must exists in any
				// tree model implementation which has nodes which can have
				// non-unique child nodes.
				return i;
			}
		}
		return -1;
	}

	@Override
	public boolean isLeaf(final Object node) {
		return getChildCount(node) == 0;
	}

	private static boolean isSimpleType(final Object node) {
		// TODO this method should probably belong to the bean wrapper
		return node instanceof String || node instanceof Number || node instanceof Date;
	}

	@Override
	public void addTreeModelListener(final TreeModelListener l) {
		modelListeners.add(l);
	}

	@Override
	public void removeTreeModelListener(final TreeModelListener l) {
		modelListeners.remove(l);
	}

	@Override
	public void valueForPathChanged(final TreePath path, final Object newValue) {
		// TODO Auto-generated method stub

	}

}
